home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / questpgr.c < prev    next >
Encoding:
Text File  |  1993-08-01  |  11.6 KB  |  495 lines  |  [TEXT/R*ch]

  1. ericptr_t,int,int,FILE    *));
  2. static struct qtmsg * FDECL(construct_qtlist, (long));
  3. static unsigned NDECL(class_index);
  4. static const char * NDECL(intermed);
  5. static const char * NDECL(neminame);
  6. static const char * NDECL(guardname);
  7. static const char * NDECL(homebase);
  8. static struct qtmsg * FDECL(msg_in, (struct qtmsg *,int));
  9. static void FDECL(convert_arg, (CHAR_P));
  10. static void NDECL(convert_line);
  11. static void FDECL(deliver_by_pline, (struct qtmsg *));
  12. static void FDECL(deliver_by_window, (struct qtmsg *));
  13.  
  14. static char    in_line[80], cvt_buf[64], out_line[128];
  15. static struct    qtlists    qt_list;
  16. static    FILE    *msg_file;
  17.  
  18. #ifdef DEBUG
  19. static void NDECL(dump_qtlist);
  20.  
  21. static void
  22. dump_qtlist()    /* dump the character msg list to check appearance */
  23. {
  24.     struct    qtmsg    *msg;
  25.     long    size;
  26.  
  27.     for (msg = qt_list.chclass; msg->msgnum > 0; msg++) {
  28.         pline("msgnum %d: delivery %c",
  29.             msg->msgnum, msg->delivery);
  30.         more();
  31.         (void) fseek(msg_file, msg->offset, SEEK_SET);
  32.         deliver_by_window(msg);
  33.     }
  34. }
  35. #endif /* DEBUG */
  36.  
  37. static void
  38. Fread(ptr, size, nitems, stream)
  39. genericptr_t    ptr;
  40. int    size, nitems;
  41. FILE    *stream;
  42. {
  43.     int cnt;
  44.  
  45.     if ((cnt = fread(ptr, size, nitems, stream)) != nitems) {
  46.  
  47.         panic("PREMATURE EOF ON QUEST TEXT FILE!\nExpected %d bytes - got %d\n",
  48.             (size * nitems), (size * cnt));
  49.     }
  50. }
  51.  
  52. static struct qtmsg *
  53. construct_qtlist(hdr_offset)
  54. long    hdr_offset;
  55. {
  56.     struct qtmsg *msg_list;
  57.     int    n_msgs;
  58.  
  59.     (void) fseek(msg_file, hdr_offset, SEEK_SET);
  60.     Fread(&n_msgs, sizeof(int), 1, msg_file);
  61.     msg_list = (struct qtmsg *) alloc((n_msgs+1)*sizeof(struct qtmsg));
  62.  
  63.     /*
  64.      * Load up the list.
  65.      */
  66.     Fread((genericptr_t)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file);
  67.  
  68.     msg_list[n_msgs].msgnum = -1;
  69.     return(msg_list);
  70. }
  71.  
  72. void
  73. load_qtlist()
  74. {
  75.  
  76.     int    n_classes, i;
  77.     char    qt_classes[N_HDR];
  78.     long    qt_offsets[N_HDR];
  79.  
  80.     msg_file = fopen_datafile(QTEXT_FILE, RDMODE);
  81.     if (!msg_file)
  82.         panic("\rCANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE);
  83.  
  84.     /*
  85.      * Read in the number of classes, then the ID's & offsets for
  86.      * each header.
  87.      */
  88.  
  89.     Fread(&n_classes, sizeof(int), 1, msg_file);
  90.     Fread(qt_classes, sizeof(char), n_classes, msg_file);
  91.     Fread(qt_offsets, sizeof(long), n_classes, msg_file);
  92.  
  93.     /*
  94.      * Now construct the message lists for quick reference later
  95.      * on when we are actually paging the messages out.
  96.      */
  97.  
  98.     qt_list.common = qt_list.chclass = (struct qtmsg *)0;
  99.  
  100.     for (i = 0; i < n_classes; i++) {
  101.         if (qt_classes[i] == COMMON_ID)
  102.         qt_list.common = construct_qtlist(qt_offsets[i]);
  103.         else if (qt_classes[i] == pl_character[0])
  104.         qt_list.chclass = construct_qtlist(qt_offsets[i]);
  105.     }
  106.  
  107.     if (!qt_list.common || !qt_list.chclass)
  108.         impossible("load_qtlist: cannot load quest text.");
  109. #ifdef DEBUG
  110.     dump_qtlist();
  111. #endif
  112.     return;    /* no ***DON'T*** close the msg_file */
  113. }
  114.  
  115. static struct qt_matrix {
  116.  
  117.     const char *intermed;    /* intermediate goal text */
  118.     const char *homebase;    /* leader's "location" */
  119.  
  120.     short    ldrnum,        /* mons[] indicies */
  121.         neminum,
  122.         guardnum;
  123.  
  124.     short    mtyp1, mtyp2;    /* monster types for enemies 0 == random */
  125.     char    msym1, msym2;    /* monster classes for enemies */
  126.  
  127.     short    artinum;    /* index of quest artifact */
  128.  
  129. } qt_matrix[] = {
  130.  
  131. /* A */ { "the tomb of the Toltec Kings",
  132.       "the College of Archeology",
  133.       PM_LORD_CARNARVON, PM_MINION_OF_HUHETOL, PM_STUDENT,
  134.       0, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY,
  135.       ART_ORB_OF_DETECTION },
  136.  
  137. /* B */ { "the Duali Oasis",
  138.       "the Camp of the Duali Tribe",
  139.       PM_PELIAS, PM_THOTH_AMON, PM_CHIEFTAIN,
  140.       PM_OGRE, PM_TROLL, S_OGRE, S_TROLL,
  141.       ART_HEART_OF_AHRIMAN },
  142.  
  143. /* C */ { "the Dragon's Lair",
  144.       "the Caves of the Ancestors",
  145.       PM_SHAMAN_KARNOV, PM_CHROMATIC_DRAGON, PM_NEANDERTHAL,
  146.       PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT,
  147.       ART_SCEPTRE_OF_MIGHT },
  148.  
  149. /* E */ { "the Goblins' Cave",
  150.       "the great Circle of Earendil",
  151.       PM_EARENDIL, PM_GOBLIN_KING, PM_HIGH_ELF,
  152.       PM_URUK_HAI, PM_OGRE, S_ORC, S_OGRE,
  153.       ART_PALANTIR_OF_WESTERNESSE },
  154.  
  155. /* E */ { "the Goblins' Cave",
  156.       "the great Circle of Elwing",
  157.       PM_ELWING, PM_GOBLIN_KING, PM_HIGH_ELF,
  158.       PM_URUK_HAI, PM_OGRE, S_ORC, S_OGRE,
  159.       ART_PALANTIR_OF_WESTERNESSE },
  160.  
  161. /* H */ { "the Temple of Coeus",
  162.       "the Temple of Epidaurus",
  163.       PM_HIPPOCRATES, PM_CYCLOPS, PM_ATTENDANT,
  164.       PM_GIANT_RAT, PM_SNAKE, S_RODENT, S_YETI,
  165.       ART_STAFF_OF_AESCULAPIUS },
  166.  
  167. /* K */ { "the Isle of Glass",
  168.       "Camelot Castle",
  169.       PM_KING_ARTHUR, PM_IXOTH, PM_PAGE,
  170.       PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY,
  171.       ART_MAGIC_MIRROR_OF_MERLIN },
  172.  
  173. /* P */ { "the Temple of Nalzok",
  174.       "the Great Temple",
  175.       PM_ARCH_PRIEST, PM_NALZOK, PM_ACOLYTE,
  176.       PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH,
  177.       ART_MITRE_OF_HOLINESS },
  178.  
  179. /* R */ { "the Asassins' Guild Hall",
  180.       "the Thieves' Guild Hall",
  181.       PM_MASTER_OF_THIEVES, PM_MASTER_ASSASSIN, PM_THUG,
  182.       PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA,
  183.       ART_MASTER_KEY_OF_THIEVERY },
  184.  
  185. /* S */ { "the Shogun's Castle",
  186.       "the castle of the Taro Clan",
  187.       PM_LORD_SATO, PM_ASHIKAGA_TAKAUJI, PM_NINJA,
  188.       PM_WOLF, PM_STALKER, S_DOG, S_STALKER,
  189.       ART_TSURUGI_OF_MURAMASA },
  190.  
  191. #ifdef TOURIST
  192. /* T */ { "the Thieves' Guild Hall",
  193.       "the Traveller's Aid Office",
  194.       PM_TWOFLOWER, PM_MASTER_OF_THIEVES, PM_GUIDE,
  195.       PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR,
  196.       ART_YENDORIAN_EXPRESS_CARD },
  197. #endif
  198.  
  199. /* V */ { "the cave of Surtur",
  200.       "the Shrine of Destiny",
  201.       PM_NORN, PM_LORD_SURTUR, PM_WARRIOR,
  202.       PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT,
  203.       ART_ORB_OF_FATE },
  204.  
  205. /* W */ { "the Tower of Darkness",
  206.       "the Tower of the Balance",
  207.       PM_WIZARD_OF_BALANCE, PM_DARK_ONE, PM_APPRENTICE,
  208.       PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH,
  209.       ART_EYE_OF_THE_AETHIOPICA },
  210.  
  211. /* - */ { "", "", 0, 0, 0, 0, 0, 0, 0, 0 }
  212. };
  213.  
  214. static unsigned
  215. class_index()
  216. {
  217.     switch (pl_character[0]) {
  218.  
  219.         case 'A':    return(0);
  220.         case 'B':    return(1);
  221.         case 'C':    return(2);
  222.         case 'E':    return((unsigned)(3+flags.female));
  223.         case 'H':    return(5);
  224.         case 'K':    return(6);
  225.         case 'P':    return(7);
  226.         case 'R':    return(8);
  227.         case 'S':    return(9);
  228. #ifdef TOURIST
  229.         case 'T':    return(10);
  230.         case 'V':    return(11);
  231.         case 'W':    return(12);
  232.         default:    return(13);
  233. #else
  234.         case 'V':    return(10);
  235.         case 'W':    return(11);
  236.         default:    return(12);
  237. #endif
  238.     }
  239. }
  240.  
  241. const char *
  242. ldrname()    /* return your class leader's name */
  243. {
  244.     int i = qt_matrix[class_index()].ldrnum;
  245. /*    return(mons[qt_matrix[class_index()].ldrnum].mname); */
  246.     return(mons[i].mname);
  247. }
  248.  
  249. static const char *
  250. intermed()    /* return your intermediate target string */
  251. {
  252.     return(qt_matrix[class_index()].intermed);
  253. }
  254.  
  255. boolean
  256. is_quest_artifact(otmp)
  257. struct obj *otmp;
  258. {
  259.     return((boolean)(otmp->oartifact == qt_matrix[class_index()].artinum));
  260. }
  261.  
  262. static const char *
  263. neminame()    /* return your class nemesis' name */
  264. {
  265.     return(mons[qt_matrix[class_index()].neminum].mname);
  266. }
  267.  
  268. static const char *
  269. guardname()    /* return your class leader's guard monster name */
  270. {
  271.     return(mons[qt_matrix[class_index()].guardnum].mname);
  272. }
  273.  
  274. static const char *
  275. homebase()    /* return your class leader's location */
  276. {
  277.     return(qt_matrix[class_index()].homebase);
  278. }
  279.  
  280. boolean
  281. leaderless()    /* return true iff leader is dead */
  282. {
  283.     int i = qt_matrix[class_index()].ldrnum;
  284.     return((boolean)(u.nr_killed[i] > 0));
  285. }
  286.  
  287. static struct qtmsg *
  288. msg_in(qtm_list, msgnum)
  289. struct qtmsg *qtm_list;
  290. int    msgnum;
  291. {
  292.     struct qtmsg *qt_msg;
  293.  
  294.     for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++)
  295.         if (qt_msg->msgnum == msgnum) return(qt_msg);
  296.  
  297.     return((struct qtmsg *)0);
  298. }
  299.  
  300. static void
  301. convert_arg(c)
  302. char c;
  303. {
  304.     register const char *str;
  305.  
  306.     switch (c) {
  307.  
  308.         case 'p':    str = plname;
  309.             break;
  310.         case 'c':    str = pl_character;
  311.             break;
  312.         case 'r':    str = rank_of(u.ulevel, pl_character[0], flags.female);
  313.             break;
  314.         case 'R':    str = rank_of(MIN_QUEST_LEVEL, pl_character[0],
  315.                               flags.female);
  316.             break;
  317.         case 's':    str = (flags.female) ? "sister" : "brother";
  318.             break;
  319.         case 'S':    str = (flags.female) ? "daughter" : "son";
  320.             break;
  321.         case 'l':    str = ldrname();
  322.             break;
  323.         case 'i':    str = intermed();
  324.             break;
  325.         case 'o':    str = the(artiname(qt_matrix[class_index()].artinum));
  326.             break;
  327.         case 'n':    str = neminame();
  328.             break;
  329.         case 'g':    str = guardname();
  330.             break;
  331.         case 'H':    str = homebase();
  332.             break;
  333.         case 'a':    str = align_str(u.ualignbase[0]);
  334.             break;
  335.         case 'A':    str = align_str(u.ualign.type);
  336.             break;
  337.         case 'd':    str = u_gname();
  338.             break;
  339.         case 'D':    str = align_gname(A_LAWFUL);
  340.             break;
  341.         case 'C':    str = "chaotic";
  342.             break;
  343.         case 'N':    str = "neutral";
  344.             break;
  345.         case 'L':    str = "lawful";
  346.             break;
  347.         case 'x':    str = Blind ? "sense" : "see";
  348.             break;
  349.         case '%':    str = "%";
  350.             break;
  351.          default:    str = "";
  352.             break;
  353.     }
  354.     Strcpy(cvt_buf, str);
  355. }
  356.  
  357. static void
  358. convert_line()
  359. {
  360.     char *c, *cc;
  361.  
  362.     cc = out_line;
  363.     for (c = xcrypt(in_line); *c; c++) {
  364.  
  365.         *cc = 0;
  366.         switch(*c) {
  367.  
  368.         case '\r':
  369.         case '\n':
  370.             *(++cc) = 0;
  371.             return;
  372.  
  373.         case '%':
  374.             if (*(c+1)) {
  375.                 convert_arg(*(++c));
  376.                 switch (*(c+1)) {
  377.  
  378.                 case 'A': Strcat(cc, An(cvt_buf));
  379.                     cc += strlen(cc);
  380.                     c++;
  381.                     continue; /* for */
  382.                 case 'a': Strcat(cc, an(cvt_buf));
  383.                     cc += strlen(cc);
  384.                     c++;
  385.                     continue; /* for */
  386.  
  387.                 case 'C': cvt_buf[0] = highc(cvt_buf[0]);
  388.                     c++;
  389.                     break;
  390.  
  391.                 case 'P': cvt_buf[0] = highc(cvt_buf[0]);
  392.                 case 'p': Strcpy(cvt_buf, makeplural(cvt_buf));
  393.                         c++; break;
  394.  
  395.                 default: break;
  396.                 }
  397.                 Strcat(cc, cvt_buf);
  398.                 cc += strlen(cvt_buf);
  399.                 break;
  400.             }    /* else fall through */
  401.  
  402.         default:
  403.             *cc++ = *c;
  404.             break;
  405.         }
  406.     }
  407.     *cc = 0;
  408.     return;
  409. }
  410.  
  411. static void
  412. deliver_by_pline(qt_msg)
  413. struct qtmsg *qt_msg;
  414. {
  415.     long    size;
  416.  
  417.     for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
  418.         (void) fgets(in_line, 80, msg_file);
  419.         convert_line();
  420.         pline(out_line);
  421.     }
  422.  
  423. }
  424.  
  425. static void
  426. deliver_by_window(qt_msg)
  427. struct qtmsg *qt_msg;
  428. {
  429.     long    size;
  430.     winid datawin = create_nhwindow(NHW_TEXT);
  431.  
  432.     for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
  433.         (void) fgets(in_line, 80, msg_file);
  434.         convert_line();
  435.         putstr(datawin, 0, out_line);
  436.     }
  437.     display_nhwindow(datawin, TRUE);
  438.     destroy_nhwindow(datawin);
  439. }
  440.  
  441. void
  442. com_pager(msgnum)
  443. int    msgnum;
  444. {
  445.     struct qtmsg *qt_msg;
  446.  
  447.     if (!(qt_msg = msg_in(qt_list.common, msgnum))) {
  448.         impossible("com_pager: message %d not found.", msgnum);
  449.         return;
  450.     }
  451.  
  452.     (void) fseek(msg_file, qt_msg->offset, SEEK_SET);
  453.     if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg);
  454.     else             deliver_by_window(qt_msg);
  455.     return;
  456. }
  457.  
  458. void
  459. qt_pager(msgnum)
  460. int    msgnum;
  461. {
  462.     struct qtmsg *qt_msg;
  463.  
  464.     if (!(qt_msg = msg_in(qt_list.chclass, msgnum))) {
  465.         impossible("qt_pager: message %d not found.", msgnum);
  466.         return;
  467.     }
  468.  
  469.     (void) fseek(msg_file, qt_msg->offset, SEEK_SET);
  470.     if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11"))
  471.         deliver_by_pline(qt_msg);
  472.     else    deliver_by_window(qt_msg);
  473.     return;
  474. }
  475.  
  476. struct permonst *
  477. qt_montype()
  478. {
  479.     int class = class_index();
  480.  
  481.     if (rn2(5)) {
  482.         if (qt_matrix[class].mtyp1 && rn2(5) &&
  483.              !(mons[qt_matrix[class].mtyp1].geno & G_GENOD))
  484.                 return(&mons[qt_matrix[class].mtyp1]);
  485.         return(mkclass(qt_matrix[class].msym1,0));
  486.     }
  487.     if (qt_matrix[class].mtyp2 && rn2(5) &&
  488.          !(mons[qt_matrix[class].mtyp1].geno & G_GENOD))
  489.             return(&mons[qt_matrix[class].mtyp2]);
  490.     return(mkclass(qt_matrix[class].msym2,0));
  491. }
  492. #endif /* MULDGN */
  493.  
  494. /*questpgr.c*/
  495.